#include "VirtualPianoApp.h"
#include "GlutCallbacks.h"


VirtualPianoApp::VirtualPianoApp () : _isInitialed (false) {}

VirtualPianoApp::~VirtualPianoApp () {}

void VirtualPianoApp::initial (int argc, char** argv, short interval)
{
	glutInit (&argc, argv);
	g_controller = this;
	_isInitialed = true;
	_interval = interval;
}

void VirtualPianoApp::createWindow (char* title, int width, int height)
{
	glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutCreateWindow (title);
	glutReshapeFunc (g_reshapeFunc);
	glutDisplayFunc (g_displayFunc);
	glutIdleFunc (g_idleFunc);
	glutMouseFunc (g_mouseFunc);
	glutMotionFunc (g_motionFunc);
	glutKeyboardFunc (g_keyboardFunc);
	glutSpecialFunc (g_specialFunc);
	glutTimerFunc (_interval, g_timerFunc, _interval);
	if (width <= 0 || height <= 0)
		glutFullScreen ();
	else
		glutReshapeWindow (width, height);
}

void VirtualPianoApp::run ()
{
	glutMainLoop ();
}

void VirtualPianoApp::registerWindowEventConsumer (WindowEventConsumer* consumer)
{
	for (size_t i = 0; i < _windowEventConsumers.size (); ++i)
		if (_windowEventConsumers[i] == consumer)
			return;
	_windowEventConsumers.push_back (consumer);
}

void VirtualPianoApp::registerNormalInputEventConsumer (NormalInputEventConsumer* consumer)
{
	for (size_t i = 0; i < _normalInputEventConsumers.size (); ++i)
		if (_normalInputEventConsumers[i] == consumer)
			return;
	_normalInputEventConsumers.push_back (consumer);
}

void VirtualPianoApp::registerPianoKeyEventConsumer (PianoKeyEventConsumer* consumer)
{
	for (size_t i = 0; i < _pianoKeyEventConsumers.size (); ++i)
		if (_pianoKeyEventConsumers[i] == consumer)
			return;
	_pianoKeyEventConsumers.push_back (consumer);
}

void VirtualPianoApp::registerPianoKeyEventProducer (PianoKeyEventProducer* producer)
{
	for (size_t i = 0; i < _pianoKeyEventProducers.size (); ++i)
		if (_pianoKeyEventProducers[i] == producer)
			return;
	_pianoKeyEventProducers.push_back (producer);
}

void VirtualPianoApp::reshapeFunc (int x, int y)
{
	for (size_t i = 0; i < _windowEventConsumers.size (); ++i)
		_windowEventConsumers[i]->handleResizeEvent (x, y);
}

void VirtualPianoApp::displayFunc ()
{
	for (size_t i = 0; i < _windowEventConsumers.size (); ++i)
		_windowEventConsumers[i]->handleRenderEvent ();
}

void VirtualPianoApp::idleFunc ()
{
	glutPostRedisplay ();
}

void VirtualPianoApp::mouseFunc (int button, int state, int x, int y)
{
	for (size_t i = 0; i < _normalInputEventConsumers.size (); ++i) {
		if (state == GLUT_DOWN)
			_normalInputEventConsumers[i]->handleMouseDownEvent (button, x, y);
		else
			_normalInputEventConsumers[i]->handleMouseUpEvent (button, x, y);
	}
}

void VirtualPianoApp::motionFunc (int x, int y)
{
	for (size_t i = 0; i < _normalInputEventConsumers.size (); ++i)
		_normalInputEventConsumers[i]->handleMouseDragEvent (x, y);
}

void VirtualPianoApp::keyboardFunc (unsigned char key, int x, int y)
{
	for (size_t i = 0; i < _normalInputEventConsumers.size (); ++i)
		_normalInputEventConsumers[i]->handleKeyboardEvent (key, false);
}

void VirtualPianoApp::specialFunc (int key, int x, int y)
{
	for (size_t i = 0; i < _normalInputEventConsumers.size (); ++i)
		_normalInputEventConsumers[i]->handleKeyboardEvent (key, true);
}

void VirtualPianoApp::timerFunc ()
{
	for (size_t i = 0; i < _pianoKeyEventProducers.size (); ++i)
		_pianoKeyEventProducers[i]->detectEvent ();
	PianoKeyEvent e;
	for (size_t i = 0; i < _pianoKeyEventProducers.size (); ++i)
		e = e.merge (_pianoKeyEventProducers[i]->getEvent ());
	for (size_t i = 0; i < _pianoKeyEventConsumers.size (); ++i)
		_pianoKeyEventConsumers[i]->handleEvent (e);
}